/***************************************************************
                       ctg2chr.c
written by CAS
this file contains all functions for Ctg->Chr on Main menu
***************************************************************/
#include "clam.h"
#include <float.h>
#include <gtk/gtkwidget.h>   
#include <search.h>

#define NUM_CHR 200 

extern GtkWidget *ctg_window;
extern void show_help();
extern FILE *graphQueryOpen();  
extern void Zproj_show_position();
extern int Zbatch_flag;

void ClamCtgChr();
static void CtgChrOnly(),  scanText();

int gCtgChr;
/* rules for Ctg->Chr */
static int sd_weight=2;
static int fw_weight=2;
static int pl_weight=1;
static int ignore_one_PL=0;
static int ignore_one_FW_oneclone=1;
static int ignore_one_FW_multictg=1;
static int ignore_multi_chr=2;
static int multi_chr_hitfactor=2;
static int multi_chr_evidence=2;
static int distance=100;

void* lsearch_fpc(const void* key, const void* base, int* nmemb, int size, int(*compar)(const void*, const void*));

char sdText[10], fwText[10], plText[10], hitText[10], evidText[10], distText[10];
int sdBox, fwBox, plBox, hitBox, evidBox, distBox;
int PLArc, FWonecloneArc, FWmultictgArc, multichrArc1, multichrArc2;

/* for assigning ctg->chr */
static void pickg();
static void assign_position_to_ctg();
static int cnt_plus, cnt_minus, cnt_assign, cnt_star, cnt_amp, cnt_ex;
static int cnt_flip=0, cnt_multiclust=0, cnt_ambiguous=0;
static char dist_text[20],multi_text[20];
static int anchor_size;
static int FWcnt1;
static char abbrev[3];

static struct fw {
  char chr[10];
  int index;
  int pos;
} *FW;

struct bin {
   char chr[10];                      /* or Lg */
   int total;                        /* total of FW+PL+SD */
   int score;                        /* total of FW+PL+SD */
   int clones;                       /* total clone hits (SD is always 1) */
   int unique;                       /* number of unique clones */
};

static int compare_chr(struct bin *p1, struct bin *p2){
  return strcmp(p1->chr, p2->chr);
}

/**********************************************************/
int Get_ctg_chr(char *chr_msg, char *outstr) {
char *ptr,*ptr2, tmp[CTGMSG_SZ];

     strcpy(tmp,chr_msg);
     if ((ptr = strstr(tmp,Proj.label_abbrev))==NULL) return 0;
     ptr = (char *)&ptr[strlen(Proj.label_abbrev)];
     if ((ptr2 = strstr(ptr,"{"))!=NULL || (ptr2=strstr(ptr,"["))!=NULL) ptr2[0]='\0';
     sscanf(ptr,"%s", outstr);

return 1;
}
/**********************************************************/
int Get_chr_prefix(char *anchor, char *chr) {
int nchr;
char cchr;

     if (!Proj.generic_grpnames) {
        if (sscanf(anchor,"%d",&nchr)==1) sprintf(chr,"%d",nchr);
        else if (sscanf(anchor,"%c",&cchr)==1) sprintf(chr,"%c", cchr);
        else  {
           cchr = '\0';
           return 0;
        }
     }
     else {
        strncpy(chr,anchor,9);
     }
     return 1;
}
/**********************************************************/
int get_nchr_xchr(char *anchor, int *nchr, char *xchr) {
int n;
char x;

     *nchr=0; *xchr=' ';
     if (anchor[0] == '\0') return 0;
     if (anchor[0] == '-') return 0;
     if (sscanf(anchor,"%d",&n)==1) {*nchr = n; return 1;}
     if (sscanf(anchor,"%c",&x)==1) {*xchr = x; return 1;}
     return 0;
}
/**********************************************************
 A SD clone generally has a remark saying what the real clone name is
 This trys to find it. 
**************************************************************/
static void extract_clone_from_SD_remark(char *remark, char *clone){
   int i;
                 /* cari 2/24/04 added looking for blank */
   for(i=0;(remark[i]!=',') && remark[i]!=' ' && 
             (i<CLONE_SZ-1) && (remark[i]!='\0');i++){
      clone[i]=remark[i];
   }
   clone[i]='\0';
   if(strstr(clone,"BAC") != NULL) strcpy(clone,&clone[4]);      
   if(strstr(clone,"\'IGF\'") != NULL) strcpy(clone,&clone[6]);  
}
/**************************************************/
static void pad_string(char *str, char *t1, char *t2)
{
int i;
   strcpy(str,t1);
   for (i=strlen(t1); i<anchor_size; i++) str[i] = ' ';
   str[i] = '\0';
   strcat(str,t2);
}
/**************************************************/
static void add_chr_msg(int ctg, char *str)
{
char *ptr, newstr[500], oldstr[500];
int i;
     if (!contigs[ctg].noedit_chr) {
         strncpy(contigs[ctg].chr_msg, str, CTGMSG_SZ-1);
         return;
     }
      /* keep everything up to [ or  from original */
     strcpy(newstr, contigs[ctg].chr_msg);
     for (i=0; i<100 && newstr[i]!='\0'; i++)
        if (newstr[i]=='[' || newstr[i]=='{') {
           newstr[i]= '\0';
           break;
        }
     for (i--; i>0 && newstr[i]==' '; i--);
     newstr[i+1]='\0';

      /* remove Chr or Lg from str and extra blanks */
     if ((ptr = strstr(str,Proj.label_abbrev)) !=NULL) 
        for (i=0; i< strlen(Proj.label_abbrev); i++) ptr[i]='.'; 
     sprintf(oldstr," {%s}",str);

     strcat(newstr, oldstr);
     strncpy(contigs[ctg].chr_msg, newstr, CTGMSG_SZ-1);
}

/************************************************
         DEF: ctgchrinit
************************************************/
static int ctgchrinit()
{
int i;
  for (FWcnt1=anchor_size = i=0; i<arrayMax(markerdata); i++) {
      if (arrp(markerdata, i, MARKER)->anchor) FWcnt1++; 
  }
  if (strcmp(Proj.label_abbrev,"Lg")==0) {
      anchor_size=3;
      strcpy(abbrev,"lg");
  }
  else {
      anchor_size=5;
      strcpy(abbrev,"ch");
  }
  FW = (struct fw *) malloc(FWcnt1 * sizeof(struct fw));
  NOMEM3(FW, "frameworks",0);

return 1;
}
/************************************************
         DEF: ZCtgChrUpdate
called by Edit Contig Remark when chr is set
called by edit.c when contigs are merged or split
**************************************************/
void ZCtgChrUpdate(int ctg)
{
  if (!ctgchrinit()) return;
  if (contigs[ctg].count!=0) CtgChrOnly(ctg, 0);
  free(FW);
}
/**********************************************
         DEF: ZCtgChrAll
*************************************************/
void ZCtgChrAll ()
{
char str[200];
int i;

  if (Proj.label_abbrev[0]=='\0') {
     sprintf(str,"To use this function, you must load a framework file\n containing chromosome, linkage group, etc. information.  See Help.");
     graphMessage(str);
     return;
  }
  if (!Zbatch_flag)
      printf("\nAssign Contigs to %s:\n",Proj.anchor_label);
  scanText();
     
  ctgchrinit();
  cnt_plus=cnt_minus=cnt_assign=cnt_star=cnt_amp=cnt_ex=0;
  cnt_flip=cnt_multiclust=cnt_ambiguous=0;
  dist_text[0]=multi_text[0]='\0';
  
  /** main loop through contigs **/
  for (i=1; i<=max_contig; i++) {
     if (contigs[i].count!=0) CtgChrOnly(i, 0);
  }
  free(FW);

  if (!Zbatch_flag) { /* cari 7-5-4 */
    printf("  Assign %d\n Single hit (-) %d\n  Mult %s (+) %d\n  SD only (*) %d\n",
      cnt_assign, cnt_minus, Proj.label_abbrev, cnt_plus, cnt_star); 
    printf("  Single anchor/Mult Chrs (&) %d\n  Anchors too distant (!) %d\n",
           cnt_amp, cnt_ex);
    printf("Positioning:\n");
    printf("  Contigs flipped %d\n  Multi Cluster %d\n  Ambiguous %d\n",
           cnt_flip,  cnt_multiclust, cnt_ambiguous);
    fflush(stdout); /* cari 2/4/4 for cronjob */
    Zproj_show_position(); 
  }
}

/*************************************************************
                  DEF: check other contigs
*************************************************************/
static int check_other_contigs(int index, int ctg)
{
int num;
struct markerctgpos *pos;
struct markerclone *cl;
MARKER *marker = arrp(markerdata,index,MARKER);

    for (pos = marker->pos; pos!=NULL; pos=pos->next)
    {
         if (pos->ctg == ctg) continue;
         num=0;
         if(arrp(acedata,marker->cloneindex,CLONE)->ctg == pos->ctg)
              num++;
         for (cl = marker->nextclone; cl!=NULL; cl = cl->nextclone)
              if(arrp(acedata,cl->cloneindex,CLONE)->ctg == pos->ctg)
                   num++;
         if (num > 1) return 1;
    }
return 0;
}
/************************************************************
                ZCtgChrCOnly
*************************************************************/
static void CtgChrOnly(int ctg, int prt) 
{
register int j,  k;
struct markertop *mkptr;
struct marker *marker;
struct remark *last;
CLONE *clp;
char  *ptr=NULL, cx, str[1000], tmp[80], tmp2[80];
int numfw=0, x, cnt=0;
struct bin chr[NUM_CHR], tmp_chr, *chrptr;
int amp=0, seq=0, fw=0, pl=0, found, minus, plus, star, numchr=0;
int unique_flag;

   if (Proj.label_abbrev[0]=='\0') return;

   if (contigs[ctg].noedit_chr==0) contigs[ctg].chr_msg[0]='\0';
   if (contigs[ctg].noedit_pos==0) contigs[ctg].chr_pos = -1;

   for (j=0; j<NUM_CHR; j++) chr[j].chr[0] = '\0';
   for (j=0; j<FWcnt1; j++) FW[j].index = -1;
   seq=fw=pl=0;

   for (j=contigs[ctg].start; j != -1; j = clp->next)
   {
       clp = arrp(acedata,j,CLONE);
       unique_flag=0;

            /* go thru remarks for Chr - FSD only does Chromosomes  */
                  /* cari 9feb05 - check for cancelled */
       if (strstr(clp->clone, "sd1")!=NULL && clp->clone[0] != '!')  
       { 
           for (found=x=0, last=clp->remark; last !=NULL && !found; 
						last = last->next)
           {
               if ((ptr = strstr(last->message,"Chr"))!=NULL) found=1;
           }
           if (!found) goto FIND_FW_MARKERS;
           if ((k = sscanf(ptr,"Chr%d", &x))==1) 
                sprintf(tmp_chr.chr,"%d",x);
           else if ((k = sscanf(ptr,"Chr%c", &cx))==1) 
                sprintf(tmp_chr.chr,"%c",cx);
           else {
                printf("Cannot parse %s remark %s\n",clp->clone, last->message);
                goto FIND_FW_MARKERS;
           }
           if(numchr > NUM_CHR){
                printf("Exceeded maximum number of chromosomes!\n");
                goto FIND_BEST_CHR;
           }
           tmp_chr.total= tmp_chr.score = tmp_chr.clones=  0;
	   chrptr = (struct bin *) lsearch_fpc(&tmp_chr, chr, &numchr, 
                        sizeof(struct bin), (void *) compare_chr);
	   chrptr->total++;
	   chrptr->score+= sd_weight;
	   chrptr->clones++; 
           seq++;
        }
FIND_FW_MARKERS: ;
        for (mkptr = clp->marker; mkptr != NULL; mkptr=mkptr->nextmarker)
        {
            marker = arrp(markerdata, mkptr->markerindex, MARKER);
            if (marker->anchor==FALSE) continue;
            if (!Get_chr_prefix(marker->anchor_bin,tmp_chr.chr)) continue;

            for (found=k=0; k<numfw+1 && !found; k++) 
            {
                if (FW[k].index==mkptr->markerindex) { /* marker found before */
                    strcpy(FW[k].chr, tmp_chr.chr);
                    chrptr = (struct bin *) lsearch_fpc(&tmp_chr, chr, &numchr,
                              sizeof(struct bin), (void *) compare_chr);
                    if (unique_flag==0) {
                        unique_flag=1;
                        chrptr->unique++;
                    }
                    chrptr->clones++;
                    found=1;
                }
                else if (FW[k].index == -1) {
                    numfw++;
                    FW[k].index= mkptr->markerindex;
                    FW[k].pos= marker->anchor_pos;
                    strcpy(FW[k].chr, tmp_chr.chr);

                    if (numchr > NUM_CHR){
                        printf("Exceeded maximum number of chromosomes!\n");
                        goto FIND_BEST_CHR;
                    }
	            tmp_chr.total= tmp_chr.score = tmp_chr.clones= 0;
                    tmp_chr.unique = 0;
	            chrptr = (struct bin *) lsearch_fpc(&tmp_chr, chr, &numchr, 
                              sizeof(struct bin), (void *) compare_chr);
                    chrptr->clones++;
                    chrptr->total++;
                    if (unique_flag==0) {
                        unique_flag=1;
                        chrptr->unique++;
                    }

		    if (marker->frame_type == FRAME) {
                         chrptr->score+= fw_weight;
                         fw++;
                    }
                    else {
                         chrptr->score+= pl_weight;
                         pl++;
                    }
                    found=1;
                }
             }
         }
     }
FIND_BEST_CHR:;
     if (seq==0 && fw==0 && pl==0) {
         add_chr_msg(ctg,"");
         return;
     }
     x = -1;
     minus=star=plus=0;
     if (seq==1 && fw==0 && pl==0) {
         star = 1;
     } 
     else if (seq==0 && fw==0 && pl==1 && ignore_one_PL) {
          minus = 1;
     } 
     else if (seq==0 && (fw+pl)==1) {
        if (ignore_one_FW_oneclone && chr[0].clones==1) minus=1;
        if (ignore_one_FW_multictg) { 
            if (check_other_contigs(FW[0].index,ctg)) amp = 1;
        }
     }
     if (star || minus || amp) goto PRT_CHR_MSG;

        /* find highest hit contig */
     for (cnt=0, k=0,x=0; k<numchr; k++) {
        if (chr[k].score == chr[x].score &&
            chr[k].clones > chr[x].clones) x = k;
        if (chr[k].score > chr[x].score) x = k;

        if (ignore_multi_chr==2) cnt += chr[k].clones;
        else if (ignore_multi_chr==1) cnt+= chr[k].score;
     } 
     if (ignore_one_FW_oneclone && chr[x].unique==1 && (fw+pl)>1) minus=1;
     else if (ignore_multi_chr==2) {
        cnt -= chr[x].clones;
        if (chr[x].clones < cnt * multi_chr_hitfactor) plus=1;  
     }
     else {
        cnt -= chr[x].score;
        if (chr[x].score < cnt * multi_chr_evidence) plus=1;  
     }

PRT_CHR_MSG: ;
         /* contract chr_msg */
     if (minus) { pad_string(str,"-","["); cnt_minus++; }
     else if (star)  { pad_string(str,"*","["); cnt_star++; }
     else if (amp)   { pad_string(str,"&","["); cnt_amp++; }
     else if (plus)  { pad_string(str,"+","["); cnt_plus++;
         x= -1;
         if (prt) printf("Ctg%-4d: \n", ctg);
     }
     else {
         sprintf(tmp,"%s%s ",Proj.label_abbrev,chr[x].chr);
         sprintf(tmp2,"[%d",chr[x].total);
         pad_string(str,tmp,tmp2);
         cnt_assign++;
     }
  
     for (k=0; k<numchr; k++) {
        if (k!=x) {
            sprintf(tmp," %s%s/%d", abbrev,chr[k].chr, chr[k].total);
            strcat(str,tmp);
        }
        if (plus && prt) {
            if (x==k) sprintf(tmp,"* %s%s",Proj.label_abbrev, chr[k].chr);
            else sprintf(tmp,"  %s%s",Proj.label_abbrev, chr[k].chr);
            pad_string(tmp2,tmp," ");
            printf("%s total %-2d score %-2d clones %-d\n",
                tmp2, chr[k].total, chr[k].score, chr[k].clones);
        }
     }
     if (fw> 0) { sprintf(tmp," Fw%d",fw); strcat(str,tmp); }
     if (pl> 0) { sprintf(tmp," Pm%d",pl); strcat(str,tmp); }
     if (seq>0) { sprintf(tmp," Seq%d",seq); strcat(str,tmp); }
     strcat(str,"]");
     add_chr_msg(ctg,str);
     assign_position_to_ctg(ctg);
} 
/****************************************************
            DEF: assign_position_to_ctg
******************************************************/
static void assign_position_to_ctg(int ctg)
{
int i, j, k, kk;
struct markertop *mkptr;
struct marker *marker;
struct markerctgpos *pos;
CLONE *clp;
char  ctg_chr[10], chr[10], str[50];
int max_fpc_pos, min_fpc_pos;
int found, acnt=0, amax=1000;
struct {
  float pos;
  int index;
  int nctg;
  int fpc_pos;
  int cluster;
  int frame;
} anchor[1000], tmp_anchor;
float ctg_pos=0.0;
void flip_contig(), contigsAlloc();

   if (!Get_ctg_chr(contigs[ctg].chr_msg,ctg_chr)) {
        goto DONE;
   }
   for (j=contigs[ctg].start; j != -1; j = clp->next)
   {
       clp = arrp(acedata,j,CLONE);
             /* go thru markers looking for anchors */
       for (mkptr = clp->marker; mkptr != NULL; mkptr=mkptr->nextmarker)
       {
           kk = mkptr->markerindex;
           marker = arrp (markerdata, kk, MARKER);
           if (marker->anchor==FALSE) continue;
           if (!Get_chr_prefix(marker->anchor_bin, chr)) continue;
           if (strcmp(chr, ctg_chr)!=0) continue;
           for (found=k=0; k<acnt && !found; k++) 
                if (anchor[k].index==kk) found=1;
           if (found) continue;

           anchor[acnt].pos = marker->anchor_pos;
           anchor[acnt].index = kk;
           anchor[acnt].nctg = 0;
           anchor[acnt].cluster = 0;
           anchor[acnt].frame = (marker->frame_type==FRAME) ? 1 : 0;
           for (pos = marker->pos; pos!=NULL; pos=pos->next){
                anchor[acnt].nctg++;
                if (pos->ctg==ctg) anchor[acnt].fpc_pos = pos->pos;
           }
           ctg_pos += marker->anchor_pos;
           acnt++;
           if (acnt>=amax) {
               fprintf(stderr,"Greater than %d anchors for contig %d\n",amax,ctg);
               break;
           }
       }
   }
   if (acnt == 0) {
       fprintf(stderr,"Ctg%d (%s%s) has no anchors??\n",ctg,
               Proj.label_abbrev,ctg_chr);
       goto DONE;
   }
   if (acnt==1) {
       if (contigs[ctg].noedit_pos==0)
          contigs[ctg].chr_pos = anchor[0].pos;
       goto DONE;
   }
   /* sort */
   for (k=0; k<acnt; k++) 
   {
        for (kk=k+1; kk<acnt; kk++) 
           if (anchor[k].pos > anchor[kk].pos) {
               tmp_anchor = anchor[k];
               anchor[k] = anchor[kk];
               anchor[kk] = tmp_anchor;
           } 
   }
   /* find clusters */
   for (found=i=kk=0; i<acnt-1; i++) {
       if (anchor[i+1].pos - anchor[i].pos < distance) {
           if (found==0) {
               kk++;
               found=1;
               anchor[i+1].cluster = anchor[i].cluster = kk;
           } else anchor[i+1].cluster  = kk;
       } else found =  0;
   }
   if (acnt > 1 && kk==0) { /* anchors too far apart */
       if (contigs[ctg].noedit_pos==0) contigs[ctg].chr_pos = -1;
                         /* fix the chr_msg */
       if (contigs[ctg].noedit_chr==0) {
               /* get rid of chr and add ! */
           for (i=0; i<strlen(contigs[ctg].chr_msg) && 
              contigs[ctg].chr_msg[i] != '['; i++)
                 contigs[ctg].chr_msg[i] = ' ';
           contigs[ctg].chr_msg[0] = '!'; 
       }
       else {
               /* find {, then get rid of chr and add ! */
           for (i=0; i<strlen(contigs[ctg].chr_msg) && 
              contigs[ctg].chr_msg[i] != '{'; i++);
           contigs[ctg].chr_msg[++i] = '!'; 
           for (i++; i<strlen(contigs[ctg].chr_msg) && 
              contigs[ctg].chr_msg[i] != '['; i++)
                 contigs[ctg].chr_msg[i] = ' ';
       } 
       cnt_ex++;
       goto DONE;
   }
   if (contigs[ctg].noedit_pos) goto DONE;

   if (kk>1) { /* a cluster of all placements will be ignored */
       int good=0, fw, pl;
       for (k=0; k<kk; k++) {
          for (fw=pl=i=0; i<acnt; i++) { 
            if (anchor[i].cluster==k) {
                fw++;
                if (anchor[i].frame==1) pl++;
            }
          }
          if (fw==pl){  
            for (i=0; i<acnt; i++) 
              if (anchor[i].cluster==k) anchor[i].cluster=0;
          } else good++;
       } 
       if (good > 1) {
          sprintf(str," %d clusters",good);
          if (strlen(contigs[ctg].chr_msg) + 14 < CTGMSG_SZ)
             strcat(contigs[ctg].chr_msg,str);
          contigs[ctg].chr_pos = -1;
          cnt_multiclust++;
          goto DONE;
       }
       if (good ==0) {
          if (strlen(contigs[ctg].chr_msg) + 14 < CTGMSG_SZ)
             strcat(contigs[ctg].chr_msg," Ambiguous");
          contigs[ctg].chr_pos = -1;
          cnt_ambiguous++;
          fprintf(stderr,"Ctg%d has ambiguous anchoring - can't pos\n",ctg);
          goto DONE;
       }
   }
   min_fpc_pos = max_fpc_pos = -1;
   for (ctg_pos=k=i=0; i<acnt; i++) 
       if (anchor[i].cluster != 0) {
           ctg_pos += anchor[i].pos;
           k++;
           if (anchor[i].frame==1) {
             if (min_fpc_pos==-1) min_fpc_pos = i;
             max_fpc_pos = i;
           }
       }
   contigs[ctg].chr_pos = ctg_pos/k;
   if (min_fpc_pos > -1 && max_fpc_pos > -1)
      if (anchor[min_fpc_pos].fpc_pos > anchor[max_fpc_pos].fpc_pos)
        if (anchor[min_fpc_pos].pos != anchor[max_fpc_pos].pos)
        {
          flip_contig(ctg);
          PRTMESS=0; 
          cnt_flip++;
        }
DONE: ;
}
/**********************************************************
                    DEF: ZmvCtgFW
**********************************************************/
struct tmp_ctg {
  int oldctg;
  float pos;
  int nchr;
  char xchr;
  int flip;
} *Ctg; 

/****************************/
static int sortctg(const void *orig_a, const void *orig_b)
{
  struct tmp_ctg *a;
  struct tmp_ctg *b;
  int val=0;
  int chrPart(); /* see proj.c */

  a = (struct tmp_ctg *)orig_a;
  b = (struct tmp_ctg *)orig_b;
  
  if ((val = chrPart(a->nchr,b->nchr,a->xchr,b->xchr))!=0) return val;

  if (a->pos < b->pos) return -1;
  if (a->pos > b->pos) return 1;
  return 0;
}

/****************************/
static void move(from, to) {
register int k;
CLONE *clpk;
void move_selected();

  if (contigs[from].count!= 0) {
    for (k= contigs[from].start; k != -1; k = clpk->next) {
       clpk = arrp(acedata, k, CLONE);
       clpk->selected = TRUE;
       if (clpk->ctg==clpk->oldctg) clpk->oldctg=from;
     }
     move_selected(from, to, 0);
  }
}

/****************************/
static void ZmvCtgFW()
{
register int c, i, k;
char   ctg_chr[10];
int  last, from_last;
float star = 20000000.0;
float plus = 30000000.0;
float minus= 40000000.0;
float amp  = 50000000.0;
float ex  =  60000000.0;
float some = 70000000.0;
float none = 80000000.0;
float dead = 90000000.0;
char anchor_bin[ANCHOR_BIN_SZ+1];
void  contigsAlloc();
CLONE* clpk;

  if (Proj.label_abbrev[0]=='\0') {
     graphMessage("See help");
     return;
  }
  if(ctg_window!=NULL) gtk_widget_destroy(ctg_window);

  Ctg = (struct tmp_ctg *) malloc(sizeof(struct tmp_ctg) * (max_contig+10));
  NOMEM2(Ctg, "ctg");
  PRTMESS=0;

  from_last = last = max_contig;
  contigsAlloc((max_contig * 2)+1);
  
  printf("Reorder contigs based on Ctg->Chr positioning\n");
  printf(".. this can take awhile if there are many large contigs\n");
  printf(".. it is F4 interruptable - which stops after the next 100\n");
  for (c=-1, i=1; i<=from_last; i++) 
  {
     if ((i % 100) == 0) {
        if (graphInterruptCalled()) {
          printf("User Interrupt - pre-mature termination\n");
          return;
        }
        printf("Processed %d contigs...\n",i);
     }
     if (contigs[i].count == 0) continue;
     last++;
     c++;
     move(i, last);

     Ctg[c].oldctg = last; 
     Ctg[c].flip = 0; 
     Ctg[c].xchr = ' ';
     Ctg[c].nchr = 0;

     if (contigs[last].noedit_pos==0) {
        if (contigs[last].ctgstat == DEAD) {
            Ctg[c].pos = dead + (float) i;
            continue;
        }
        if (contigs[last].chr_msg[0] == '&') {
            Ctg[c].pos = amp + (float) i;
            continue;
        }
        else if (contigs[last].chr_msg[0] == '+') {
            Ctg[c].pos = plus + (float) i;
            continue;
        }
        else if (contigs[last].chr_msg[0] == '-') {
            Ctg[c].pos = minus + (float) i;
            continue;
        }
        else if (contigs[last].chr_msg[0] == '*') {
            Ctg[c].pos = star + (float) i;
            continue;
        }
        else if (contigs[last].chr_msg[0] == '!') {
            Ctg[c].pos = ex + (float) i;
            continue;
        }
        else if (contigs[last].chr_msg[0] == '\0') {
            Ctg[c].pos = none + (float)i;
            continue;
        }
     }
     Ctg[c].pos = some + (float)i;
     if (!Get_ctg_chr(contigs[last].chr_msg, anchor_bin)) continue;
     if (!Get_chr_prefix(anchor_bin, ctg_chr)) continue;
     if (!get_nchr_xchr(ctg_chr, &Ctg[c].nchr, &Ctg[c].xchr)) continue;
     if (contigs[last].chr_pos >= 0) 
            Ctg[c].pos = contigs[last].chr_pos;
  }
  printf("Sort %d contigs...\n", c+1);
  qsort(Ctg, c+1, sizeof(struct tmp_ctg), sortctg); 
  max_contig = c;

  for (i=1; i<=c+1; i++) {
     move(Ctg[i-1].oldctg, i);
     for (k= contigs[i].start; k != -1; k = clpk->next) {
        clpk = arrp(acedata, k, CLONE);
        clpk->oldctg = i;
      }
     if ((i % 100) == 0) {
        if (graphInterruptCalled()) {
          printf("User Interrupt - pre-mature termination\n");
          return;
        }
        printf("Move %d contigs...\n",i);
     }
  }
  free(Ctg);
  PRTMESS=1;
  Zproj_show_position(); 
  printf("Complete reorder contigs\n");
}
/******************************************************
               DEF: ZprocessSD
1. Find all clones with "sd" in the name and make them to SD
   Find the original fingerprinted clone and set it to SHOTGUN
2. Write out Genbank.txt for WebFPC.
3. Unbury any sequenced clone
4. Give report of clones where the fingerprint and SD clones do not match.

It has a remark "clone name, ChrN - author", e.g.
  a0083M16, Chr1 - Sasaki,t.
The "Chr" may be missing.
The clone name may be one of ours, but may not.
The fpc clone name is the genbank accession with a "sd1" suffix.

******************************************************/
void ZprocessSD()
{
int i,  cnt=0;
int index, cnt_sd=0, cnt_agi=0;
struct remark *last;
CLONE *clp, *clp2;
char   *ptr, tmp[80];
FILE *refp;
void unbury();
int Zfp_match();
char matchclone[CLONE_SZ];
  
  if (!arrayExists(bands)) 
         if (fpRead() == -1) return;

  if ((refp= fopen("genbank.webfpc.ref","w"))==NULL) {
      fprintf(stderr,"Cannot open genbank.webfpc.ref\n");
      return;
  }
  fprintf(refp,"Genbank\n");
  fprintf(refp,"Clone List:http://www.ncbi.nlm.nih.gov:80/entrez/query.fcgi?cmd=Search&db=Nucleotide&dopt=GenBank&term=\n");

/** process SD clones ***/
  for (i=0; i< arrayMax(acedata); i++) {
      clp2 = arrp(acedata, i, CLONE);
                       /* cari 9feb05  add check for cancelled */
      if (strstr(clp2->clone,"sd")==NULL && clp2->clone[0]!='!') { /* cari 16apr was != 0 */
         if (clp2->seqstat!=0 && clp2->parent != -1) 
           { printf(" 1 unbury %s\n",clp2->clone); unbury(i);}
         continue;
      }
        /* SD clone */
      cnt_sd++;
      clp2->seqstat = SD;
      clp2->seqtype = FULLX;
      if (clp2->parent != -1) 
           { printf("2 unbury %s\n",clp2->clone); unbury(i);}

          /* print into Genbank ref file */
      if ((ptr = strstr(clp2->clone,"sd1"))!=NULL && ptr[3]=='\0') {
           strncpy(tmp,clp2->clone, strlen(clp2->clone)-3);
           tmp[strlen(clp2->clone)-3] = '\0';
           fprintf(refp,"%s %s\n",clp2->clone, tmp);
      }
          /* find original clone */
      last=clp2->remark;
      if (last==NULL) continue;
      extract_clone_from_SD_remark(last->message, matchclone);

      if (!fppFind(acedata,matchclone,&index, cloneOrder)) continue;
      clp = arrp(acedata, index, CLONE);
      
      cnt_agi++;
      if (clp->seqstat!=SHOTGUN && !Zbatch_flag) 
                printf("Setting %s to SHOTGUN by %s\n",clp->clone,clp2->clone);
      clp->seqstat = SHOTGUN;
      clp->seqtype = FULLX;
      if (clp->parent != -1) 
           { printf("unbury %s\n",clp2->clone); unbury(i);}
      if (!Zbatch_flag) {
         if (!Zfp_match(i,index)) {
            sprintf(ZBuf,"%3d Bad: %15s %15s %d %1.0e : %s\n", cnt, clp->clone, 
              clp2->clone, Sz.match, Sz.prob, last->message); 
            Outlog;
            if (clp->ctg!=clp2->ctg) 
              sprintf(ZBuf,"    Ctg: %15s ctg%d %15s ctg%d\n", clp->clone, 
               clp->ctg, clp2->clone, clp2->ctg);
           else if (clp->x > clp2->y || clp->y < clp2->x)
             sprintf(ZBuf,"    Olp: %15s %d,%d %15s %d,%d\n",
               clp->clone, clp->x, clp->y, clp2->clone, clp2->x, clp2->y);
           Outlog;
           cnt++;
         }
         else {
           if (clp->ctg!=clp2->ctg) 
             sprintf(ZBuf,"*   Ctg: %15s ctg%d %15s ctg%d\n", 
                     clp->clone, clp->ctg, clp2->clone, clp2->ctg);
           else if (clp->x > clp2->y || clp->y < clp2->x)
             sprintf(ZBuf,"*   Olp: %15s %d,%d %15s %d,%d\n",
                   clp->clone, clp->x, clp->y, clp2->clone, clp2->x, clp2->y);
           Outlog;
        }
     }
  }
  fprintf(refp,"end\n"); /* cari 10/28/04 */
  fclose(refp);
  printf("SD clones %d  AGI %d   Bad %d\n",cnt_sd, cnt_agi, cnt);
}
/***************************************************************
                      help 
****************************************************************/
static void zhelp()
{
show_help("Ctg->Chr (frameworks and sd clones)","ctg2chr");
}
/*********************************************************
                  DEF: quitCtgChr
*********************************************************/
static void quitCtgChr() 
{
   if (graphActivate(gCtgChr)) 
      graphDestroy();
}
/*********************************************************
                  DEF: ClamCtgChr
*********************************************************/
static void pickg(int box,double x,double y)
{
  if(box == fwBox)      fwBox = graphTextEntry(fwText,14,0,0,NULL);
  else if(box == plBox) plBox = graphTextEntry(plText,14,0,0,NULL);
  else if(box == sdBox) sdBox = graphTextEntry(sdText,14,0,0,NULL);
  else if(box == hitBox) hitBox = graphTextEntry(hitText,14,0,0,NULL);
  else if(box == evidBox) evidBox = graphTextEntry(evidText,14,0,0,NULL);
  else if (box == PLArc) {
    ignore_one_PL = !ignore_one_PL;
    ClamCtgChr();
  }
  else if (box == FWonecloneArc) {
    ignore_one_FW_oneclone = !ignore_one_FW_oneclone;
    ClamCtgChr();
  }
  else if (box == FWmultictgArc) {
    ignore_one_FW_multictg = !ignore_one_FW_multictg;
    ClamCtgChr();
  }
  else if (box == multichrArc1) {
    ignore_multi_chr=1;
    ClamCtgChr();
  }
  else if (box == multichrArc2) {
    ignore_multi_chr=2;
    ClamCtgChr();
  }
}
static void scanText()
{
  if(graphActivate(gCtgChr)){
    sscanf(fwText,"%d",&fw_weight);
    sscanf(plText,"%d",&pl_weight);
    sscanf(sdText,"%d",&sd_weight);
    sscanf(hitText,"%d",&multi_chr_hitfactor);
    sscanf(evidText,"%d",&multi_chr_evidence);
    sscanf(distText,"%d",&distance);
  }
}

void ClamCtgChr()
{
float row;
float col=3.0;
float width=50.0;
char str[200];
static MENUOPT amenu[] = { 
    { quitCtgChr, "Close" },
    { 0, 0 } } ;

  if (!dataloaded) return;
  if(graphActivate(gCtgChr)){   
       graphPop();
  }
  else{
    gCtgChr = graphCreate (TEXT_FIT,"Ctg -> Chr",.2,.2,.46,.46);
    graphRegister (PICK, pickg) ;
  }
  graphClear();
  graphMenu(amenu);
 
  row = 1.5;
  graphButton("Process sd clones",ZprocessSD,2.0,row);
  row += 2.0;
  graphLine(0.0,row,width,row);
  row += 1.5;

  sprintf(fwText,"%d",fw_weight);
  sprintf(plText,"%d",pl_weight);
  sprintf(sdText,"%d",sd_weight);
  sprintf(hitText,"%d",multi_chr_hitfactor);
  sprintf(evidText,"%d",multi_chr_evidence);
  sprintf(distText,"%d",distance);

  graphText("Evidence weight:",2,row);
  row += 1.5;
  graphText("Framework",4,row);
  fwBox = graphTextEntry(fwText, 3, 14, row,scanText);
  graphText("Placement",18,row);
  plBox = graphTextEntry(plText, 3, 28, row,scanText);
  graphText("SD clone",32,row);
  plBox = graphTextEntry(sdText, 3, 42, row,scanText);

  row += 1.5;
  graphText("Ignore if one anchor and:",2,row);
  row += 1.5;
  col=4.0;
  PLArc = graphBoxStart();
      graphArc(col, row+0.5, 0.7, 0, 360);
      if (ignore_one_PL) graphFillArc(col, row+0.5, 0.4, 0, 360);
      graphBoxEnd();
      graphBoxDraw(PLArc, BLACK, TRANSPARENT);
  graphText("it is a Placement marker ",col+2.0,row);

  row += 1.5;
  FWonecloneArc = graphBoxStart();
      graphArc(col, row+0.5, 0.7, 0, 360);
      if (ignore_one_FW_oneclone) graphFillArc(col, row+0.5, 0.4, 0, 360);
      graphBoxEnd();
      graphBoxDraw(FWonecloneArc, BLACK, TRANSPARENT);
  graphText("it has one clone hit",col+2.0,row);

  row += 1.5;
  FWmultictgArc = graphBoxStart();
      graphArc(col, row+0.5, 0.7, 0, 360);
      if (ignore_one_FW_multictg) graphFillArc(col, row+0.5, 0.4, 0, 360);
      graphBoxEnd();
      graphBoxDraw(FWmultictgArc, BLACK, TRANSPARENT);
  graphText("it anchors multiple contigs",col+2.0,row);
  row += 1.5;

  sprintf(str,"Ignore if multiple %ss and either", Proj.label_abbrev);
  graphText(str,2,row);

  row += 1.5;
  multichrArc1 = graphBoxStart();
      graphArc(col, row+0.5, 0.7, 0, 360);
      if (ignore_multi_chr==1) graphFillArc(col, row+0.5, 0.4, 0, 360);
      graphBoxEnd();
      graphBoxDraw(multichrArc1, BLACK, TRANSPARENT);
  graphText("#score is less than",col+2.0,row);
  evidBox = graphTextEntry(evidText, 2, col+23, row,scanText);
  graphText("x all other scores",col+25,row);

  row += 1.5;
  multichrArc2 = graphBoxStart();
      graphArc(col, row+0.5, 0.7, 0, 360);
      if (ignore_multi_chr==2) graphFillArc(col, row+0.5, 0.4, 0, 360);
      graphBoxEnd();
      graphBoxDraw(multichrArc2, BLACK, TRANSPARENT);
  graphText("#clones is less than",col+2.0,row);
  hitBox = graphTextEntry(hitText, 2, col+23, row,scanText);
  graphText("x all other clone hits", col+25,row);
  row += 1.5;
  graphText("Maximum between anchors", 2.0,row);
  distBox = graphTextEntry(distText, 5, 26, row,scanText);
  graphText("cM", 31,row);
  row += 1.5;
  graphButton("Assign Ctg->Chr",ZCtgChrAll,2.0,row);

  row += 2.0;
  graphLine(0.0,row,width,row);
  row += 1.5;
  graphButton("Order Ctgs based on Chr assigment",ZmvCtgFW,2.0,row);
  row += 2.0;
  graphLine(0.0,row,width,row);
  row += 1.5;
  graphButton("Close",quitCtgChr,2.0,row);
  graphButton("Help",zhelp,10.0,row);
  graphRedraw();
}
